package com.util.vmwareops;
import com.vmware.vim25.*;
import com.vmware.vim25.mo.*;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;

public class VmTask
{
    VCConnectionPool pool = null;
    VirtualMachine vm = null;
    VirtualMachineRelocateSpec vmRelocateSpec = null;
    VirtualMachineConfigSpec vmConfigSpec = null;
    VirtualDeviceConfigSpec virtualDeviceConfigSpecs = null;
    Folder root = null;
    List<VCenterInfo> allVcInfo = null;
    List<VirtualDeviceConfigSpec> nicSpecAL = new ArrayList<VirtualDeviceConfigSpec>();
    ServiceInstance si = null;

    public VmTask(String vcName) throws InterruptedException {
        allVcInfo = VCenterOps.getAllVCInfo();
        pool = VCConnectionPoolFactory.getAllVCConnectionPool(allVcInfo).get(vcName);
        System.out.println("VMTASK&&&&&&&&&&&&&&&&&&&&&&&");
        si = pool.getConnnection();
        root = si.getRootFolder();
    }

    //关闭当前ServiceInstance
    public void closeSI() {

        pool.close(si);
    }

    public VirtualMachine getVm(Folder root, String vmName) throws RemoteException
    {
        return (VirtualMachine) new InventoryNavigator(root).searchManagedEntity("VirtualMachine", vmName);
    }

    public boolean isEmpty(String para)
    {
        return (para.isEmpty() || para == null);
    }

    public void updateNetPort(String switchType, String NetworkName, VirtualEthernetCard nic, Folder root) throws RemoteException {
        String backingType = nic.getBacking().getClass().toString();
        virtualDeviceConfigSpecs = new VirtualDeviceConfigSpec();
        String portGroupKey = null;
        String dvsUUID = null;

//        String regex = "DS_.*";aszdx
//        if (Pattern.matches(regex,NetworkName))
        //迁往分布式端口组
        if (switchType.equalsIgnoreCase("DistributedVirtualPortgroup"))
        {

            DistributedVirtualPortgroup port = (DistributedVirtualPortgroup) new InventoryNavigator(root).searchManagedEntity("DistributedVirtualPortgroup",NetworkName);
            DistributedVirtualSwitch dvs = new DistributedVirtualSwitch(root.getServerConnection(),port.getConfig().distributedVirtualSwitch);
//
            portGroupKey = port.getKey();
            dvsUUID = dvs.getUuid();

            VirtualEthernetCardDistributedVirtualPortBackingInfo nicBacking = new VirtualEthernetCardDistributedVirtualPortBackingInfo();
            DistributedVirtualSwitchPortConnection portConn = new DistributedVirtualSwitchPortConnection();

            portConn.setPortgroupKey(portGroupKey);
            portConn.setSwitchUuid(dvsUUID);

            nicBacking.setPort(portConn);
            nic.setBacking(nicBacking);

            virtualDeviceConfigSpecs.setDevice(nic);
            virtualDeviceConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.edit);
            nicSpecAL.add(virtualDeviceConfigSpecs);
        }
        //迁往标准交换机。需排除分布改标准
        else
        {
            //分布 -> 标准 排除
            if(backingType.equalsIgnoreCase("class com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo"))
            {
                System.out.println("不支持分布式端口组迁至标准");
            }
            //标准 -> 标准
            else
            {
                VirtualDeviceDeviceBackingInfo vddBackingInfo= (VirtualDeviceDeviceBackingInfo) nic.getBacking();
                vddBackingInfo.setDeviceName(NetworkName);
                nic.setBacking(vddBackingInfo);
                virtualDeviceConfigSpecs.setDevice(nic);
                virtualDeviceConfigSpecs.setOperation(VirtualDeviceConfigSpecOperation.edit);
                nicSpecAL.add(virtualDeviceConfigSpecs);
            }
        }
    }
    //自定义迁移目标配置
    public VirtualMachineRelocateSpec customMotionConfig(String vmName, String hostDestName, String dsDestName, String switchTypeBiz, String switchTypeMgt , String NetworkNameBiz,String NetworkNameMgt) throws Exception
    {
        vmRelocateSpec = new VirtualMachineRelocateSpec();

        vm = getVm(root,vmName);

        System.out.println("通过vc connection pool 获取vm信息" + vm.getName());
        if (!vm.equals(null))
        {
            //需迁移计算
            if (!isEmpty(hostDestName))
            {
                HostSystem hostDest = (HostSystem) new InventoryNavigator(root).searchManagedEntity("HostSystem", hostDestName);
                vmRelocateSpec.setHost(hostDest.getMOR());
            }
            //需迁移存储
            if (!isEmpty(dsDestName))
            {
                Datastore dsDest = (Datastore) new InventoryNavigator(root).searchManagedEntity("Datastore", dsDestName);
                vmRelocateSpec.setDatastore(dsDest.getMOR());
//                vmRelocateSpec.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.moveAllDiskBackingsAndAllowSharing);
            }
            if (isEmpty(hostDestName) && isEmpty(dsDestName))
            {
                return null;
            }

            //自定义虚机网卡信息
            //虚机device信息
            VirtualDevice[] devices= vm.getConfig().getHardware().getDevice();
            for(VirtualDevice device:devices)
            {
                //筛选网卡类的device信息
                if(device instanceof VirtualEthernetCard)
                {
                    VirtualEthernetCard nic;
                    nic = (VirtualEthernetCard) device;
                    if(nic.getDeviceInfo().getLabel().equals("Network adapter 1"))
                    {
                        updateNetPort(switchTypeBiz,NetworkNameBiz,nic,root);
                    }
                    else if(nic.getDeviceInfo().getLabel().equals("Network adapter 2"))
                    {
                        updateNetPort(switchTypeMgt,NetworkNameMgt,nic,root);
                    }
                }
            }
            VirtualDeviceConfigSpec[] vDeviceConSpecArray = nicSpecAL.toArray(new VirtualDeviceConfigSpec[nicSpecAL.size()]);
            vmRelocateSpec.setDeviceChange(vDeviceConSpecArray);
            return  vmRelocateSpec;
        }
        return null;
    }

    //自定义虚机配置
    public VirtualMachineConfigSpec customVmConfig(VirtualMachine vm, int NumCpu, int NumMem)
    {
        vmConfigSpec = new VirtualMachineConfigSpec();
        int currentCpu = vm.getConfig().hardware.numCPU;
        int currentMem = vm.getConfig().hardware.memoryMB;
        NumMem = NumMem*1024;
        if (NumCpu > currentCpu)
        {
            vmConfigSpec.setNumCPUs(NumCpu);
        }
        if (NumMem > currentMem)
        {
            vmConfigSpec.setMemoryMB((long)NumMem);
        }
        if (NumCpu  <= currentCpu && NumMem <= currentMem)
        {
            return null;
        }
        return  vmConfigSpec;
    }

    //VMotion 执行
    public void VMotion(String vmName, String hostDestName, String dsDestName, String switchTypeBiz, String switchTypeMgt , String NetworkNameBiz,String NetworkNameMgt) throws Exception
    {
        vmRelocateSpec =  customMotionConfig(vmName,hostDestName,dsDestName,switchTypeBiz,switchTypeMgt,NetworkNameBiz,NetworkNameMgt);
        //System.out.println(vm.getConfig().getHardware().getDevice()[14].backing.getClass().toString());
        if(vmRelocateSpec != null)
        {
            Task task = vm.relocateVM_Task(vmRelocateSpec, VirtualMachineMovePriority.highPriority);

            if (waitFor(task).getState() == TaskInfoState.success)
            {
                System.out.println("vMotion of " + vm.getName() + " to " + hostDestName
                        + " completed in " + "Task result: "
                        + task.getTaskInfo().getResult());
            }
            else
            {
                TaskInfo info = task.getTaskInfo();
                System.out.println("vMotion of " + vm.getName() + " to " + hostDestName
                        + " failed. Error details: " + info.getError().getFault());

            }
        }
        else {
            System.out.println("Destination Host Error");
        }
        closeSI();
    }

    //vm cpu、内存修改
    public void vmReConfig(String vcName, String vmName, int NumCpu, int NumMem) throws Exception
    {
        vm = getVm(root,vmName);
        vmConfigSpec = customVmConfig(vm,NumCpu,NumMem);
        if (vmConfigSpec != null)
        {
            Task task = vm.reconfigVM_Task(vmConfigSpec);
            if (waitFor(task).getState() == TaskInfoState.success)
            {
                System.out.println("Change of " + vm.getName() + " completed && " + "current CPU: "
                        + vm.getConfig().hardware.numCPU + "\tcurrent " +vm.getConfig().hardware.memoryMB/1024.0);
            }
            else
            {
                System.out.println("Change of " + vm.getName() + " uncompleted && " + "current CPU: "
                        + vm.getConfig().hardware.numCPU + "\tcurrent " +vm.getConfig().hardware.memoryMB/1024.0);
            }
            closeSI();
        }
        else {
            System.out.println("Input Error");
        }
    }


    public TaskInfo waitFor(Task task) throws RemoteException,
            InterruptedException {
        while (true)
        {
            TaskInfo ti = task.getTaskInfo();
            TaskInfoState state = ti.getState();
            if (state == TaskInfoState.success || state == TaskInfoState.error)
            {
                return ti;
            }
//            System.out.println("Task is running");
            Thread.sleep(1000);
        }
    }
}
